<?php

namespace app\load\service;

use app\load\loadModel\AdminModel;
use app\load\loadModel\OaModel;
use app\load\loadModel\TypeModel;
use app\load\model\oa\FlowModel;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\facade\Db;
use think\Model;

/**
 * 流程审核服务层
 */
class FlowService
{

    /**
     * 数据库表
     * @var string[]
     */
    protected $ModelName = [

        'model' => [
            1 => 'Approve', //日常审核
            2 => 'Expense', //报销
            3 => 'Invoice', //发票
            4 => 'Contract',//合同
        ],
        'content' => [
            1 => '一个日常审批', //日常审核
            2 => '一个报销审批', //报销
            3 => '一个发票审批', //发票
            4 => '一个合同审批',//合同
        ],
        'msg_title_type' => [
            2 => 22, //报销
            3 => 23, //发票
            4 => 24, //合同
        ]
    ];


    /**
     * 审核
     * @param  [    id: 32
     * content: 123
     * check_node: 1
     * check_admin_ids: 0
     * check: 1  |状态  成功  拒绝   撤回
     * type: 1  | 类型  日常审核  一个报销审批  一个发票审批  一个合同审批(暂未开发)
     * file: storage/base64_image/64d59caa2c05f.png
     * ]
     * @param $u_id | 登录用户id
     * @throws DataNotFoundException
     * @throws DbException
     * @throws Exception
     * @throws ModelNotFoundException
     */
    public function save($param, $u_id): bool
    {

        //审批详情
        $detail = Db::name($this->ModelName['model'][$param['type']])->where(['id' => $param['id']])->find();
        if (!$detail) {
            throw new Exception('审批数据不存在');
        }
        $subject = $this->ModelNameContent['content'][$param['type']] ?? '一个审核';
        $msg_title_type = $this->ModelNameContent['msg_title_type'][$param['type']] ?? $detail['type'];

        //获取审核节点
        $step = OaModel::FlowStep()
            ->where([
                'action_id' => $param['id'],
                'type' => $param['type'],
                'sort' => $detail['check_step_sort'],
                'delete_time' => 0])
            ->find();

        //通过
        if ($param['check'] == 1) {
            if (!$step) {
                throw new Exception('审核节点未找到');
            }
            $check_admin_ids = explode(",", strval($detail['check_admin_ids']));
            if (!in_array($u_id, $check_admin_ids)) {
                throw new  Exception('您没权限审核该审批');
            }
            $this->handleApproval($param, $detail, $subject, $msg_title_type, $step, $u_id);
        }

        //拒绝
        if ($param['check'] == 2) {
            if (!$step) {
                throw new Exception('审核节点未找到');
            }
            $check_admin_ids = explode(",", strval($detail['check_admin_ids']));
            if (!in_array($u_id, $check_admin_ids)) {
                throw new  Exception('您没权限审核该审批');
            }
            $this->handleRejection($param, $detail, $subject, $msg_title_type, $step, $u_id);

        }

        //撤回
        if ($param['check'] == 3) {
            if ($detail['admin_id'] != $u_id) {
                throw new  Exception('您没权限审核该审批');
            }
            $this->handleCancellation($param, $detail, $subject, $msg_title_type, $step, $u_id);
        }

        return true;
    }


    /**
     * 通过
     * @param $param
     * @param $detail
     * @param $subject
     * @param $msg_title_type
     * @param $step
     * @param $user_id
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws Exception
     * @throws ModelNotFoundException
     */
    public function handleApproval($param, $detail, $subject, $msg_title_type, $step, $user_id): bool
    {

        if ($step['flow_type'] == 4) { //多人会签
            $param = $this->handleMultiSignApproval($param, $detail, $step);
        } elseif ($step['flow_type'] == 0) { //自由审批
            $param = $this->handleFreePersonApproval($param, $detail);
        } else {//下一步审批 1当前部门负责人，2上一级部门负责人，3指定用户（任意一人），
            $param = $this->handleNextStepApproval($param, $detail);
        }
        if ($param['check_status'] == 1 && empty($param['check_admin_ids'])) {
            return to_assign(1, '找不到下一步的审批人，该审批流程设置有问题，请联系HR或者管理员');
        }
        //审核通过数据操作
        $param['last_admin_id'] = $user_id;
        $param['flow_admin_ids'] = $detail['flow_admin_ids'] . $user_id . ',';

        return $this->updateApprovalData($param, $detail, $subject, $msg_title_type, $step, $user_id);
    }

    /**
     * 多人审批
     * @param $param
     * @param $detail
     * @param $step
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    function handleMultiSignApproval($param, $detail, $step)
    {

        $check_count = OaModel::FlowRecord()
            ->where(['action_id' => $param['id'], 'type' => $param['type'], 'step_id' => $step['id']])
            ->count();
        $flow_count = explode(',', $step['flow_uids']);

        if (($check_count + 1) >= count($flow_count)) {
            $next_step = $this->getNextFlowStep($param['id'], $param['type'], $detail['check_step_sort'] + 1);
            if ($next_step) {
                $param['check_admin_ids'] = $next_step['flow_uids'];
                $param['check_step_sort'] = $detail['check_step_sort'] + 1;
                $param['check_status'] = 1;
            } else {
                $param['check_status'] = 2;
                $param['check_admin_ids'] = '';
            }
        } else {
            $param['check_status'] = 1;
            $param['check_admin_ids'] = $step['flow_uids'];
        }
        return $param;


    }

    /**
     * 自由审批
     * @param $param
     * @param $detail
     * @return mixed
     */
    function handleFreePersonApproval($param, $detail)
    {
        if ($param['check_node'] == 2) {
            $next_step = $detail['check_step_sort'] + 1;
            $flow_step = [
                'action_id' => $detail['id'],
                'sort' => $next_step,
                'type' => $param['type'],
                'flow_uids' => $param['check_admin_ids'],
                'create_time' => time()
            ];

            OaModel::FlowStep()->strict(false)->field(true)->insert($flow_step);

            $param['check_step_sort'] = $next_step;
            $param['check_status'] = 1;
        } else {
            $param['check_status'] = 2;
            $param['check_admin_ids'] = '';
        }

        return $param;
    }

    /**
     * 下一步审批
     * @param $param
     * @param $detail
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    function handleNextStepApproval($param, $detail)
    {
        $next_step = $this->getNextFlowStep($param['id'], $param['type'], $detail['check_step_sort'] + 1);

        if ($next_step) {
            if ($next_step['flow_type'] == 1) {
                $param['check_admin_ids'] = get_department_leader($detail['admin_id']);
            } elseif ($next_step['flow_type'] == 2) {
                $param['check_admin_ids'] = get_department_leader($detail['admin_id'], 1);
            } else {
                $param['check_admin_ids'] = $next_step['flow_uids'];
            }

            $param['check_step_sort'] = $detail['check_step_sort'] + 1;
            $param['check_status'] = 1;
        } else {
            $param['check_status'] = 2;
            $param['check_admin_ids'] = '';
        }
        return $param;
    }

    /**
     * 步骤
     * @param $id
     * @param $type
     * @param $checkStepSort
     * @return array|mixed|Db|Model|null
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    function getNextFlowStep($id, $type, $checkStepSort)
    {
        return OaModel::FlowStep()
            ->where(['action_id' => $id, 'type' => $type, 'sort' => $checkStepSort, 'delete_time' => 0])
            ->find();
    }

    /**
     * 更新信息，增加日志
     * @param $param | 审核参数
     * @param $detail |详情
     * @param $step | 步骤
     * @param $subject |审核信息
     * @param $msg_title_type | 类型
     * @param $user_id |用户id
     * @return bool
     * @throws DbException|Exception
     */
    public function updateApprovalData($param, $detail, $subject, $msg_title_type, $step, $user_id): bool
    {

        if ($param['check_status'] == 4) {
            $filed = 'check_step_sort,check_status,check_admin_ids';
        } else {
            $filed = 'check_step_sort,check_status,last_admin_id,flow_admin_ids,check_admin_ids';
        }

        $res = Db::name($this->ModelName['model'][$param['type']])->strict(false)
            ->field($filed)
            ->update($param);

        if (!$res) {
            throw new Exception('操作失败');
        }

        $checkData = [
            'action_id' => $detail['id'],
            'step_id' => $step['id'],
            'check_user_id' => $user_id,
            'type' => $param['type'],
            'check_time' => time(),
            'status' => $param['check'],
            'content' => $param['content'],
            'create_time' => time()
        ];
        $checkData['image'] = $param['file'] ?? '';
        OaModel::FlowRecord()->strict(false)->field(true)->insert($checkData);
        $param['uid'] = $user_id;
        api_add_log('check', $param['id'], $param, $subject);

        $msg = [
            'create_time' => date('Y-m-d H:i:s', $detail['create_time']),
            'action_id' => $detail['id'],
            'title' => TypeModel::FlowType()->where('id', $msg_title_type)->value('title'),
            'from_uid' => $detail['admin_id']
        ];

        if ($param['check_status'] == 1) {
            $users = $param['check_admin_ids'];
            sendMessage($users, ($param['type'] * 10 + 11), $msg);
        }

        if ($param['check_status'] == 2) {
            $users = $detail['admin_id'];
            sendMessage($users, ($param['type'] * 10 + 12), $msg);
        }

        //拒绝审核
        if ($param['check'] == 2) {
            $users = $detail['admin_id'];
            sendMessage($users, ($param['type'] * 10 + 13), $msg);
        }
        return true;

    }

    /**
     * 拒绝
     * @param $param
     * @param $detail
     * @param $subject
     * @param $msg_title_type
     * @param $step
     * @param $uid
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws Exception
     * @throws ModelNotFoundException
     */
    public function handleRejection($param, $detail, $subject, $msg_title_type, $step, $uid): bool
    {


        $param['check_status'] = 3;
        $param['last_admin_id'] = $uid;
        $param['flow_admin_ids'] = $detail['flow_admin_ids'] . $uid . ',';
        $param['check_admin_ids'] = '';

        if ($step['flow_type'] == 5) {
            $prev_step = $this->getPreviousFlowStep($detail['id'], $detail['type'], $detail['check_step_sort']);

            if ($prev_step) {
                $param['check_step_sort'] = $prev_step['sort'];
                $param['check_admin_ids'] = $prev_step['flow_uids'];
                $param['check_status'] = 1;
            } else {
                $param['check_step_sort'] = 0;
                $param['check_admin_ids'] = '';
                $param['check_status'] = 0;
            }
        }
        return $this->updateApprovalData($param, $detail, $subject, $msg_title_type, $step, $uid);
    }

    /**
     * 当前审核流程
     * @param $id
     * @param $type
     * @param $checkStepSort
     * @return array|mixed|Db|Model|null
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    function getPreviousFlowStep($id, $type, $checkStepSort)
    {
        return Db::name('FlowStep')
            ->where(['action_id' => $id, 'type' => $type, 'sort' => $checkStepSort - 1, 'delete_time' => 0])
            ->find();
    }

    /**
     * 撤回
     * @param $param
     * @param $detail
     * @param $subject
     * @param $msg_title_type
     * @param $step
     * @param $u_id
     * @return bool
     * @throws DbException|Exception
     */
    function handleCancellation($param, $detail, $subject, $msg_title_type, $step, $u_id): bool
    {

        $param['check_status'] = 4;
        $param['check_admin_ids'] = '';
        $param['check_step_sort'] = 0;

        return $this->updateApprovalData($param, $detail, $subject, $msg_title_type, $step, $u_id);
    }


    /**
     * 获取审核步骤人员
     * @param $id | id
     * @return array
     * @throws  Exception
     */
    public function get_flow_users($id): array
    {
        $flow = OaModel::Flow()->where(['id' => $id])->find();
        $adminModel = AdminModel::Admin();
        $flowData = unserialize($flow['flow_list']);
        if (!empty($flowData)) {
            $flowAids = [];
            foreach ($flowData as &$val) {
                $flowAids = array_merge($flowAids, explode(',', $val['flow_uids']));
            }
            $flowAids = array_unique($flowAids);
            $flowUsers = $adminModel->field('id,name,thumb')->where('id', 'in', $flowAids)->select()->toArray();
            $flowUsersMap = [];
            foreach ($flowUsers as $user) {
                $flowUsersMap[$user['id']] = $user;
            }
            foreach ($flowData as &$val) {
                $val['user_id_info'] = [];
                $userIds = explode(',', $val['flow_uids']);
                foreach ($userIds as $userId) {
                    if (isset($flowUsersMap[$userId])) {
                        $val['user_id_info'][] = $flowUsersMap[$userId];
                    }
                }
            }
        }
        $data['copy_uids'] = $flow['copy_uids'];
        $data['copy_unames'] = '';
        if ($flow['copy_uids'] != '') {
            $copy_unames = $adminModel->removeOption()->where('id', 'in', $flow['copy_uids'])->column('name');
            $data['copy_unames'] = implode(',', $copy_unames);
        }
        $data['flow_data'] = $flowData;
        return $data;
    }


    /**
     * 列表
     * @param array $where
     * @param string $filed
     * @return FlowModel[]|array|Collection
     */
    public function list(array $where, string $filed)
    {
        return OaModel::Flow()->where($where)->field($filed)
            ->filter(function ($v) {
                $data = unserialize($v['flow_list']);
                if ($v['check_type'] != 2) {
                    foreach ($data as &$vs) {
                        $vs['admin_info'] = AdminModel::Admin()->where('id', $vs['flow_uids'])
                            ->field('id,name,thumb')->find();
                    }
                }
                $v['flow_list'] = $data;
            })
            ->select();
    }


}